package com.iot08.api.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONArray;
import com.iot08.api.config.redis.RedisFilterService;
import com.iot08.api.service.supplement.KafkaService;
import com.iot08.api.utils.request.ParamHandle;
import com.iot08.api.vo.request.AddRelatedDeviceReqBodyFormVO;
import com.iot08.api.vo.request.AddRelatedDeviceReqVO;
import com.iot08.api.vo.request.GetAttentionReqVO;
import com.iot08.common.constant.CacheEnum;
import com.iot08.common.constant.Const;
import com.iot08.common.constant.ConstKafka;
import com.iot08.common.constant.ConstPush;
import com.iot08.common.entity.app.*;
import com.iot08.common.service.base.BaseService;
import com.iot08.common.utils.CollectionUtil;
import com.iot08.common.utils.DateUtil;
import com.iot08.common.utils.MessageUtils;
import com.iot08.common.utils.StringUtil;
import com.iot08.common.utils.response.ResponseEnum;
import com.iot08.common.utils.response.ResponseMap;
import com.mongodb.BasicDBObject;
import com.mongodb.client.FindIterable;
import com.mongodb.client.model.Filters;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.json.JsonWriterSettings;
import org.bson.types.ObjectId;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;

/**
 * 设备关注记录表
 * @author weichao 1299101858@qq.com
 * @version 1.0
 * @date 2/26/22 3:54 PM
 */

@Slf4j
@Service
public class DeviceAttentionService extends BaseService<DeviceAttention> {

    @Resource
    private KafkaService kafkaService;

    @Resource
    private AccountService accountService;

    @Resource
    private RedisFilterService redisFilterService;

    /**
     * 创建关注记录
     * @param deviceAttention
     * @time: 2/26/22 4:13 PM
     * @author: Weichao
     * @version 1.0
     */
    public String createNewAttention(DeviceAttention deviceAttention){
        deviceAttention.setTime(DateUtil.nowTimestampToLong());
        deviceAttention.setTimestamp(DateUtil.nowTimestampToLong());
        deviceAttention.setExpiryAt(DateUtil.getSystemExpiryAt());
        deviceAttention = this.save(deviceAttention);
        return deviceAttention.getId();
    }
    /**
     * 查找申请是否已经存在
     * @param imei 设备
     * @param apply_openid 申请人openid
     * @param openid 管理员openid
     * @time: 2/26/22 4:14 PM
     * @author: Weichao
     * @version 1.0
     */
    public long findRepeatRecord(String imei, String apply_openid, String openid){
        Query query = new Query();
        query.addCriteria(Criteria.where("openid").is(openid).and("apply_openid").is(apply_openid).and("i").is(imei));
        return this.count(query);
    }

    /**
     * 关注消息查询处理
     *
     * @time: 2020/11/19 16:31
     * @author: Rock
     * @version 1.0
     */
    public List<DeviceAttention> messageQueryHandle(Document query, Bson sort, int page, int num) {
        FindIterable<Document> document = this.findDoc(query, sort, page, num);
        List<DeviceAttention> res = new ArrayList<>();
        for (Document d : document) {
            //document 对象转换成对象
            d.put("_id", d.get("_id").toString());
            d.remove("expiryAt");
            DeviceAttention deviceAttention = this.toBean(d, DeviceAttention.class);

            deviceAttention.setId(d.get("_id").toString());
            deviceAttention.setImei(d.getString("i"));
            if (d.get("t") instanceof Long) {
                deviceAttention.setTimestamp(d.getLong("t"));
            }else{
                deviceAttention.setTimestamp(d.getDouble("t").longValue());
            }
            deviceAttention.setType(d.get("T").toString());

//
//            d.remove("T");
//            d.remove("t");
//            d.remove("i");
//            d.remove("_id");
//            documents.add(d);

            res.add(deviceAttention);
        }
        return res;
    }

    public ResponseMap list (GetAttentionReqVO vo){
//        Account account = accountService.findById(vo.getOpenid());
//        if (account == null) {
//            log.info("Account is null. params={}", vo.toString());
//            return ResponseMap.fail(ResponseEnum.STATUS2000.getCode(), ResponseEnum.STATUS2000.getMsg());
//        }
//        Double delTime = account.getDeleteNotificationtime();
//        if (delTime == null) {
//            delTime = account.getTimestamp() == null ? 0 : account.getTimestamp();
//        }
        Document query = new Document();
        //参数query处理
        ParamHandle.queryParamHandle(query, vo.getQuery());

        //记录已读
        String key = String.format("%s", vo.getOpenid());
        redisFilterService.set(key + CacheEnum.READ_USER_ATTENTION_MSG_TIME.getKey(), String.valueOf(System.currentTimeMillis() / 1000));

        query.put("openid", vo.getOpenid());
        JSONArray resList = new JSONArray();
        //关注消息查询处理
        List<DeviceAttention> messagesList = messageQueryHandle(query, Filters.eq("t", -1), 0, vo.getNum());
        Long t = null;
        for (DeviceAttention item : messagesList) {
            //消息的时间
            t = item.getTimestamp();
            if(item.getType().equals("applicationRrecord")){
                //如果是申请记录的,需要 被动设置失效(当调用接口时再行检查,使过期的失效) < 24小时
                if(Math.abs(DateUtil.nowTimestampToLong()-t) > 60*60*24){
                    //使其失效 1.删除原本的记录 2.新建2条无效的记录
                    String imei = item.getImei();
                    String name = item.getName();
                    String phone = item.getPhone();
                    String apply_openid = item.getApply_openid();
                    String adminOpenid = item.getOpenid();

                    //申请人的失效提醒记录
                    DeviceAttention overTimeRecord = new DeviceAttention();
                    overTimeRecord.setImei(imei);
                    overTimeRecord.setName(name);
                    overTimeRecord.setType("applicationOvertime");
                    overTimeRecord.setPhone(phone);
                    overTimeRecord.setApply_openid(apply_openid);
                    overTimeRecord.setOpenid(apply_openid);
                    overTimeRecord.setOpenid(item.getOpenid());
                    //推送给申请人 apply_openid
                    //你申请关注【%s】手表，管理员未及时处理，申请已失效  API.pushTitle.attention.apply.overtime
                    String msg1 = MessageUtils.getLocale("API.pushTitle.attention.apply.overtime", name);
                    overTimeRecord.setMsgTitle(msg1);
                    this.createNewAttention(overTimeRecord);
                    JSONObject overTimeRecordDic = (JSONObject) JSONObject.toJSON(overTimeRecord);
                    JSONObject pushMsgData = new JSONObject();
                    pushMsgData.put("type", ConstPush.ACCOUNT_MESSAGE);
                    pushMsgData.put("message", overTimeRecordDic);
                    kafkaService.sendPushToAccount(ConstKafka.ACCOUNT_TYPE_3, apply_openid, pushMsgData);

                    //管理员的失效提醒记录
                    DeviceAttention overTimeRecordAdmin = new DeviceAttention();
                    overTimeRecordAdmin.setImei(imei);
                    overTimeRecordAdmin.setName(name);
                    overTimeRecordAdmin.setType("applicationOvertime");
                    overTimeRecordAdmin.setPhone(phone);
                    overTimeRecordAdmin.setApply_openid(apply_openid);
                    overTimeRecordAdmin.setOpenid(adminOpenid);
                    overTimeRecordAdmin.setOpenid(item.getApply_openid());
                    //推送给被申请人 (管理员) adminOpenid
                    //用户（%s）申请关注[%s] 手表, 记录未及时处理，已失效  API.pushTitle.attention.admin.overtime
                    String msg2 = MessageUtils.getLocale("API.pushTitle.attention.admin.overtime", phone, name);
                    overTimeRecordAdmin.setMsgTitle(msg2);
                    this.createNewAttention(overTimeRecordAdmin);
                    JSONObject overTimeRecordAdminDic = (JSONObject) JSONObject.toJSON(overTimeRecordAdmin);
                    pushMsgData.put("type", ConstPush.ACCOUNT_MESSAGE);
                    pushMsgData.put("message", overTimeRecordAdminDic);
                    kafkaService.sendPushToAccount(ConstKafka.ACCOUNT_TYPE_3, adminOpenid, pushMsgData);
                    this.delById(new ObjectId(item.getId()));
                    log.info("openid:{},apply_openid:{} 申请绑定手表 imei: {}失效,推送成功（申请过期失效）", adminOpenid, apply_openid, imei);
                }
            }
            resList.add(JSONObject.toJSON(item));
        }
        ResponseMap res = ResponseMap.success();
        res.put("messages", resList);
        return res;
    }


    /**
     * @description 查询用户最新的待审核信息
     * @author cwj
     * @param [openId]
     * @return com.iot08.common.entity.app.DeviceAttention
     * @date @time 2025/4/8 16:49
     **/
    public DeviceAttention queryLatestAttentionInfo(Account account) {
        List<DeviceAttention> deviceAttentions = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(account.getDeviceMap())) {
            for (Map.Entry<String, Map<String, Object>> entry : account.getDeviceMap().entrySet()) {
                Query query = new Query();
                query.addCriteria(Criteria.where("i").is(entry.getKey()).and("T").is("applicationRrecord"));
                query.with(Sort.by(Sort.Order.desc("t"))).limit(1);
                DeviceAttention deviceAttention = this.findOne(query);
                if (!ObjectUtils.isEmpty(deviceAttention)) {
                    deviceAttentions.add(deviceAttention);
                }
            }
        }
        if(!CollectionUtils.isEmpty(deviceAttentions)) {
            deviceAttentions.sort(Comparator.comparingDouble(DeviceAttention::getTimestamp).reversed());
            DeviceAttention deviceAttention = deviceAttentions.get(0);
            return deviceAttention;
        }
        return null;
    }


    public void handle (GetAttentionReqVO vo) throws IOException {
        DeviceAttention deviceAttention = this.findById(new ObjectId(vo.getId()));
        if(deviceAttention != null){
            String msgTitle = "";
            String action = "";
            if(vo.getAgree() == 1){
                //同意
                //手表（%s）的管理员已同意您 关注手表 API.pushTitle.attention.agree
                msgTitle = MessageUtils.getLocale("API.pushTitle.attention.agree", vo.getImei());
                action = "agree";
                //调用一下添加关联设备的接口
                log.info("管理员({})同意后调用一下关联设备({})接口", vo.getOpenid(), deviceAttention.getImei());
                AddRelatedDeviceReqBodyFormVO addVo = new AddRelatedDeviceReqBodyFormVO();
                addVo.setImei(deviceAttention.getImei());
                addVo.setOpenid(deviceAttention.getApply_openid());
                //这里应该是 申请人的号码 设置成 模拟添加关联设备时,自己的号码.
                addVo.setMy_phone(deviceAttention.getPhone());
                addVo.setRelationship(deviceAttention.getRelationship());
                addVo.setRelationship_image_id(deviceAttention.getRelationship_image_id());
                ResponseMap res = accountService.addRelatedDevice(addVo, null, false);
                log.info("管理员同意后使用申请人的openid:({})调用一下关联设备({})接口结果:{}", deviceAttention.getApply_openid(), deviceAttention.getImei(), res.toString());
            }else{
                //拒绝
                //手表（%s）的管理员拒绝了您 关注手表 API.pushTitle.attention.reject
                msgTitle = MessageUtils.getLocale("API.pushTitle.attention.reject", vo.getImei());
                action = "reject";
                log.info("管理员({})拒绝 用户:{} 关注设备{}", vo.getOpenid(), deviceAttention.getApply_openid(), deviceAttention.getImei());
            }
            DeviceAttention tempAttention = new DeviceAttention();
            tempAttention.setImei(deviceAttention.getImei());
            tempAttention.setName(deviceAttention.getName());
            tempAttention.setPhone(deviceAttention.getPhone());
            tempAttention.setType("checkResults");
            tempAttention.setAction(action);
            tempAttention.setOpenid(vo.getOpenid());
            tempAttention.setTimestamp(DateUtil.nowTimestampToLong());
            this.createNewAttention(tempAttention);
            tempAttention.setId(null);
            tempAttention.setOpenid(deviceAttention.getApply_openid());
            this.createNewAttention(tempAttention);

            //发送给申请者的推送通知
            JSONObject pushMsgData = new JSONObject();
            pushMsgData.put("type", ConstPush.ACCOUNT_MESSAGE);

            JSONObject message = new JSONObject();
            message.put("imei", deviceAttention.getImei());
            message.put("type", "checkedResults");
            message.put("name", deviceAttention.getName());
            message.put("phone", deviceAttention.getPhone());
            message.put("msgTitle", msgTitle);
            message.put("action", action);
            message.put("timestamp", DateUtil.nowTimestampToLong());

            pushMsgData.put("message", message);
            kafkaService.sendPushToAccount(ConstKafka.ACCOUNT_TYPE_3, deviceAttention.getApply_openid(), pushMsgData);
            //最后处理掉此记录
            this.delById(new ObjectId(deviceAttention.getId()));
        }

    }

    public void dels (GetAttentionReqVO vo){
        //该接口没有带 messageIds参数时，则删除所有消息，有的话则删除指定的消息
        if(vo.getMessageIds() == null){
            //全部
            Query query = new Query().addCriteria(Criteria.where("openid").is(vo.getOpenid()));
            this.delByQuery(query);
        }else{
            //URL解码
            JSONArray msgIds = JSONArray.parseArray(vo.getMessageIds());
            List<ObjectId> ids = new ArrayList<>();
            if(ids.size() > 0){
                for (int i = 0; i < msgIds.size(); i++) {
                    if (ObjectId.isValid(msgIds.getString(i))) {
                        ids.add(new ObjectId(msgIds.getString(i)));
                    }
                }
                this.delByIds(ids);
            }
        }

    }

    public static void main(String[] args){
        DeviceAttention item = new DeviceAttention();
        item.setOpenid("aaaa");
        item.setName("测试");
        item.setTimestamp((long) 54646546);
        item.setExpiryAt(new Date());
        JSONObject jsonItem = (JSONObject) JSONObject.toJSON(item);
        System.out.println(String.format("jsonItem:%s", jsonItem.toJSONString()));

    }
}
